home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / str.exe / STR.CPP < prev    next >
C/C++ Source or Header  |  1993-03-17  |  23KB  |  870 lines

  1. //
  2. // str.cpp : str class implementation
  3. // Author  : Roy S. Woll
  4. //
  5. // Copyright (c) 1993 by Roy S. Woll
  6. // You may distribute this source freely as long as you leave all files
  7. // in their original form, including the copyright notice as is.
  8. //
  9. //
  10. // Version 2.11     3/17/93
  11. //    Friend operator ">>" changed to use str's buffer if > 256.
  12. //    Assign operator optimized to not copy referenced data.
  13. //    Fix - Remove member function now transfers only necessary characters
  14. //
  15. // Version 2.00     12/5/92
  16. //    Support searching/replacing, regular expressions, case sensitivity
  17. //
  18. //    Fixed the following bugs.
  19. //       1. Fixed size strings
  20. //       2. Concatenating a substr
  21. //
  22. //    Changed member functions pad/strip to modify instance, and introduced
  23. //    friend functions pad/strip.
  24. //
  25. // Version 1.00     10/20/92
  26. //
  27. #include <ctype.h>
  28. #include <string.h>
  29. #include <iostream.h>
  30. #include <iomanip.h>
  31. #include <assert.h>
  32.  
  33. #include "str.h"
  34. #include "dynstream.h"
  35.  
  36. int strnicmp(const char * s1, const char * s2, unsigned n);
  37. int stricmp(const char * s1, const char * s2);
  38. char * strlwr(char *);
  39. char * strupr(char *);
  40.  
  41. inline int min(int x, int y){if (x<y) return x; else return y;}
  42. inline int max(int x, int y){if (x>y) return x; else return y;}
  43.  
  44. // Define macro used to adjust internal debugging counters for object
  45. #ifdef DEBUG_STR     
  46. #define STR_SUB_COUNTERS(count)   count--;
  47. #define STR_ADD_COUNTERS(count)   count++;Total##count++;
  48. #else
  49. #define STR_SUB_COUNTERS(count)
  50. #define STR_ADD_COUNTERS(count)
  51. #endif
  52.  
  53.  
  54. static str::strdata NullData = {0, 0, 1, 0, 1, ""};
  55.  
  56. // Create and map to new buffer, and if previous buffer exists,
  57. //   transfer to new buffer.
  58. // Delete old buffer if unreferenced.
  59. char * str::getNewBuffer(int newbufsize){
  60.    return  getNewBuffer(length(), newbufsize);
  61. };
  62.  
  63. char * str::getNewBuffer(int len, int newbufsize)
  64. {
  65.    if (data==&NullData){
  66.      if (memsize_incr) newbufsize = max(newbufsize, memsize_init);
  67.      else newbufsize = memsize_init;
  68.    }
  69.    else {
  70.      if (!memsize_incr) return NULL;
  71.      if ((newbufsize>data->cursize) || (!newbufsize) )
  72.         newbufsize = max(newbufsize, data->cursize + memsize_incr);
  73.      else newbufsize = max(newbufsize, memsize_init);
  74.    }
  75.    if (!newbufsize) newbufsize = memsize_incr;       // don't allow 0 size
  76.  
  77.    strdata * newdata;
  78.    init(newdata, newbufsize, 0);
  79.    setNewBuffer(newdata, newbufsize, len);
  80.  
  81.    return data->buf;
  82. };
  83.  
  84. // Map to new buffer and if previous buffer exists, transfer to new buffer
  85. void str::setNewBuffer(strdata * newdata,
  86.            int newbufsize, int len){
  87.  
  88.    newdata->curlength = data->curlength;
  89.    newdata->strChange = data->strChange;
  90.  
  91.  
  92.    if (data->mystream) {
  93.  
  94.      // Use existing stream
  95.       newdata->mystream = data->mystream;
  96.  
  97.      // update existing stream to map to new buffer
  98.       newdata->mystream->rdbuf()->setNewBuffer(newdata->buf, newbufsize);
  99.  
  100.      // update stream length next time stream is called for previous data
  101.       if (!data->strChange){
  102.          data->strChange = 1;
  103.          data->curlength = data->mystream->rdbuf()->out_waiting();
  104.       };
  105.  
  106.      // force previous data to have unitialized stream
  107.       data->mystream = NULL;
  108.    };
  109.  
  110.    memcpy(newdata->buf, data->buf, len);
  111.  
  112.    if (!(--data->refcount)) {
  113.         delete data;
  114.         STR_SUB_COUNTERS(AllocationCount)
  115.    }
  116.  
  117.  
  118.    data = newdata;
  119. };
  120.  
  121.  
  122. void str::init(strdata*& adata, int cursize,
  123.           int curlength)
  124. {
  125.    STR_ADD_COUNTERS(AllocationCount)
  126.    if (!cursize) cursize=STR_DEFAULT_MEMINCR;
  127.  
  128.    adata =
  129.       (strdata *) new char [(cursize+1)+
  130.                             sizeof(strdata)-strdata::STR_DEBUG_BUFSIZE];
  131.    if (!adata){
  132.       cout << "Failed to allocate memory (" << cursize << ")" << endl;
  133.       assert(adata);
  134.    };
  135.  
  136.    adata->cursize=cursize;
  137.    adata->curlength=curlength;
  138.    adata->refcount=1;
  139.    adata->mystream=NULL;
  140.    adata->strChange=1;
  141. };
  142.  
  143.  
  144. // Construct an empty str
  145. str::str (void):
  146.           data(&NullData),
  147.           memsize_init(0), memsize_incr(STR_DEFAULT_MEMINCR),
  148.           flags(defaultFlags)
  149. {
  150.    STR_ADD_COUNTERS(ObjectCount)
  151.    data->refcount++;
  152. };
  153.  
  154. // Construct an empty str
  155. str::str (int p_bufsize, int p_incr):
  156.           data(&NullData),
  157.           memsize_init(p_bufsize), memsize_incr(p_incr),
  158.           flags(defaultFlags)
  159. {
  160.    STR_ADD_COUNTERS(ObjectCount)
  161.    data->refcount++;
  162. };
  163.  
  164.  
  165. // Construct a str containing substr, char *
  166. str::str (const char * s1, const char * s2):
  167.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  168.           flags(defaultFlags)
  169. {
  170.  
  171.    STR_ADD_COUNTERS(ObjectCount)
  172.    int len1=(s1 ? strlen(s1) : 0);
  173.    int len2=(s2 ? strlen(s2) : 0);
  174.  
  175.    init(data, len1+len2, len1+len2);
  176.    memcpy(data->buf, s1, len1);
  177.    memcpy(data->buf+len1, s2, len2);
  178. };
  179.  
  180. // Construct a str containing char *, substr
  181. str::str (const char * s1, const substr& s2):
  182.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  183.           flags(defaultFlags)
  184. {
  185.  
  186.    STR_ADD_COUNTERS(ObjectCount)
  187.    int len1=(s1 ? strlen(s1) : 0);
  188.    int len2=s2.length();
  189.  
  190.    init(data, len1+len2, len1+len2);
  191.    memcpy(data->buf, s1, len1);
  192.    memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
  193. };
  194.  
  195. // Construct a str containing two char *
  196. str::str (const substr& s1, const char * s2):
  197.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  198.           flags(defaultFlags)
  199. {
  200.  
  201.    STR_ADD_COUNTERS(ObjectCount)
  202.    int len1= s1.length();
  203.    int len2= (s2 ? strlen(s2) : 0);
  204.  
  205.    init(data, len1+len2, len1+len2);
  206.    memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
  207.    memcpy(data->buf+len1, s2, len2);
  208. };
  209.  
  210. // Construct a str containing two substr
  211. str::str (const substr& s1, const substr& s2):
  212.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  213.           flags(defaultFlags)
  214. {
  215.  
  216.    STR_ADD_COUNTERS(ObjectCount)
  217.    int len1= s1.length();
  218.    int len2= s2.length();
  219.  
  220.    init(data, len1+len2, len1+len2);
  221.    memcpy(data->buf,      &s1.mystr->data->buf[s1.posReplace], len1);
  222.    memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
  223. };
  224.  
  225. // Construct a str containing char *
  226. str::str (const char * s, int p_bufsize, int p_incr):
  227.           memsize_init(p_bufsize),memsize_incr(p_incr),
  228.           flags(defaultFlags)
  229. {
  230.    STR_ADD_COUNTERS(ObjectCount)
  231.    if (!s) return;
  232.  
  233.    int curlength, cursize;
  234.  
  235.    if (memsize_incr==0) {  // not allowed to expand
  236.       curlength = min(strlen(s), memsize_init);
  237.       cursize = memsize_init;
  238.    }
  239.    else {
  240.       curlength=strlen(s);
  241.       cursize = max(curlength, memsize_init);
  242.    };
  243.  
  244.    init(data, cursize, curlength);
  245.    memcpy(data->buf, s, curlength);
  246. };
  247.  
  248. // Construct a str containing str
  249. str::str (const str& s, int p_bufsize, int p_incr):
  250.           memsize_init(p_bufsize),memsize_incr(p_incr),
  251.           flags(defaultFlags)
  252. {
  253.    STR_ADD_COUNTERS(ObjectCount)
  254.  
  255.    if (memsize_incr) {
  256.       data = s.data;
  257.       data->refcount++;
  258.    }
  259.    else {
  260.       int curlength = min(s.length(), memsize_init);
  261.       init(data, memsize_init, curlength);
  262.       memcpy(data->buf, s, curlength);
  263.    };
  264.  
  265. };
  266.  
  267.  
  268. // Return a ostream that maps to the same buffer as the str
  269. ostream& str::stream(int pos){
  270.    return stream().seekp(pos);
  271. };
  272.  
  273. // Return a ostream that maps to the same buffer as the str
  274. ostream& str::stream(void){
  275.  
  276.   //
  277.   // check if need to allocate more memory
  278.   //
  279.    int allocsize=0;
  280.    if (data==&NullData) allocsize = memsize_init;    // first time allocating
  281.    else if (length()>=size()) allocsize = size()+memsize_incr;
  282.    _checkMemAllocation(allocsize);
  283.  
  284.   //
  285.   // Create stream if it doesn't exist
  286.   // otherwise tell dynstream about me in case it needs to extend buf
  287.   //
  288.    if (!data->mystream) data->mystream = new dynstream(this);
  289.    else data->mystream->rdbuf()->set_str(this);
  290.  
  291.  
  292.   //
  293.   // update stream length if length has been changed by str operators.
  294.   // Not done every time in case stream operation was the last operation 
  295.   // to change the leng